#ifndef USER_DEVICE_H
#define USER_DEVICE_H

#include "gpio.h"
#include "user_global.h"
#include "freq_table.h"

// server_status定义
#define STATUS_IDLE                     0
#define STATUS_BUSY                     0xFFFF

///////////////////////////////////////////////////////////////////////////////////////////////

#define S1_RESET_BUFFER_STEP              (long)(S1_RESET_BUFFER_DISTANCE  * SPR / S1_PERIMETER)
#define S1_LIMIT_BUFFER_STEP              (long)(S1_LIMIT_BUFFER_DISTANCE  * SPR / S1_PERIMETER)
#define S1_STOP_BUFFER_STEP               (long)(S1_STOP_BUFFER_DISTANCE  * SPR / S1_PERIMETER)
#define V1_LOCK_STEP                      (long)(V1_LOCK_DISTANCE  * SPR / S1_PERIMETER)
#define V1_RELEASE_STEP                   (long)(V1_RELEASE_DISTANCE  * SPR / S1_PERIMETER)

#define S2_RESET_BUFFER_STEP              (long)(S2_RESET_BUFFER_DISTANCE  * SPR / S1_PERIMETER)
#define S2_LIMIT_BUFFER_STEP              (long)(S1_LIMIT_BUFFER_DISTANCE  * SPR / S1_PERIMETER)
#define S2_STOP_BUFFER_STEP               (long)(S2_STOP_BUFFER_DISTANCE  * SPR / S1_PERIMETER)
#define V2_LOCK_STEP                      (long)(V1_LOCK_DISTANCE  * SPR / S1_PERIMETER)
#define V2_RELEASE_STEP                   (long)(V1_RELEASE_DISTANCE  * SPR / S1_PERIMETER)

#define S3_RESET_BUFFER_STEP              (long)(S3_RESET_BUFFER_DISTANCE  * SPR / S3_PERIMETER)
#define S3_LIMIT_BUFFER_STEP              (long)(S1_LIMIT_BUFFER_DISTANCE  * SPR / S3_PERIMETER)
#define S3_STOP_BUFFER_STEP               (long)(S3_STOP_BUFFER_DISTANCE  * SPR / S3_PERIMETER)
#define V3_LOCK_STEP                      (long)(V1_LOCK_DISTANCE  * SPR / S3_PERIMETER)
#define V3_RELEASE_STEP                   (long)(V1_RELEASE_DISTANCE  * SPR / S3_PERIMETER)

#define S4_RESET_BUFFER_STEP              (long)(S4_RESET_BUFFER_DISTANCE  * SPR / S4_PERIMETER)
#define S4_LIMIT_BUFFER_STEP              (long)(S4_LIMIT_BUFFER_DISTANCE  * SPR / S4_PERIMETER)
#define S4_STOP_BUFFER_STEP               (long)(S4_STOP_BUFFER_DISTANCE  * SPR / S4_PERIMETER)
#define V4_LOCK_STEP                      (long)(V4_LOCK_DISTANCE  * SPR / S4_PERIMETER)
#define V4_RELEASE_STEP                   (long)(V4_RELEASE_DISTANCE  * SPR / S4_PERIMETER)
////////////////////////////////////////////////////////////////////////////////////
#define HCLK                    120000000
#define APB1_PRESCAL            4
#define APB2_PRESCAL            2
#define PCLK1                   HCLK / APB1_PRESCAL     // 60M
#define PCLK2                   HCLK / APB2_PRESCAL     // 30M

// 获取更新系统时间
#define TIMER_START(stamp)                    do{(stamp) = SystemTick(); stamp = ((stamp) == TIMER_STOPED ? (TIMER_STOPED + 1):(stamp));}while(0)
#define TIMER_STOP(stamp)                     do{(stamp) = TIMER_STOPED;}while(0)
#define TIMER_OUT(stamp,usec)                 ((SystemTick() - stamp) > (usec))

#define OPEN 0          //打开
#define CLOSE 1         //关闭

extern UU16 system_tick;

//Device IO
////////////////////////////////////////////
#define  IO_S1()                              HAL_GPIO_ReadPin(SWITCH1_GPIO_Port,SWITCH1_Pin)
#define  IO_S2()                              HAL_GPIO_ReadPin(SWITCH2_GPIO_Port,SWITCH2_Pin)
#define  IO_S3()                              HAL_GPIO_ReadPin(SWITCH3_GPIO_Port,SWITCH3_Pin)
#define  IO_S4()                              HAL_GPIO_ReadPin(SWITCH4_GPIO_Port,SWITCH4_Pin)
//led 闪烁
#define LED_BLINK()                           gpio_bit_toggle(LED_GPIO_Port,LED_Pin)


// when debug code with debuger,it possibely reset because of the watchdg tick keep working even if break
#if USE_WATCHDG
    #define Update_WatchDog()                 wwdgt_counter_update(107)
#else
    #define Update_WatchDog()                 __NOP()
#endif

#define ReadPin(id)                           HAL_GPIO_ReadPin(gportin[id].port,gportin[id].pin)
#define IO_Read(id)                           (id ? (gportin[id].inverse ? !ReadPin(id) : ReadPin(id)) : 0)

#define SetPin(id)                            HAL_GPIO_WritePin(gportout[id].port, gportout[id].pin, SET)
#define ResetPin(id)                          HAL_GPIO_WritePin(gportout[id].port, gportout[id].pin, RESET)
#define IO_Act(id, act)                       HAL_GPIO_WritePin(gportout[id].port, gportout[id].pin, act ? SET : RESET)
#define IO_Set(id)                            gportout[id].inverse ? ResetPin(id) : SetPin(id)
#define IO_Reset(id)                          gportout[id].inverse ? SetPin(id) : ResetPin(id)


#define US_TO_TICK(us1)                       (us1)
#define US_TO_TICK_UL(us1)                    (us1)
#define ONE_MS                                US_TO_TICK(1)                     // 1us
#define TWO_MS                                US_TO_TICK(2)                     // 1us
#define FIVE_MS                               US_TO_TICK(5)                     // 10us
#define TEN_MS                                US_TO_TICK(10)                    // 10us
#define TWENTY_MS                             US_TO_TICK(20)                    // 10us
#define THREE_S                               (ulong)US_TO_TICK(3000000)        // 3s
#define TWENTY_MIN                            (ulong)US_TO_TICK(1200000000)     // 20min
//#define TICK_TO_US(tick)                    ((ulong)((tick)*(TIM3_PRESCAL * 1e6 / TIM3_SYSCLK)))

ushort SystemTickLow(void);                         // 系统时钟低16位, X0.5us
ushort SystemTickHigh(void);                        // 系统时钟高16位, X32.768ms
ulong SystemTick(void);                             // 系统时钟, X0.5us
void Delay_Tick(ushort tick);
void Delay_Tick_Loop(ulong tick);
#define Delay_us(n)                            Delay_Tick(US_TO_TICK(n))

extern unsigned char server_address;
extern bit pending_action;                  // 新动作
extern uchar pending_role;

typedef __packed struct
{
  ushort s_home_step_buffer[MACHINE_COUNT - 1];
} DevRunParam;

extern DevRunParam dev_run_param;


void Device_Init(void);
void Update_IO(void);
void Update_Ready(uchar sen, ushort exist, ushort ready, ulong *stamp);
void Main_Loop(void);
void Process_Main_Loop(void);
void Process_Action(void);

void Tst_Systick_Timer6(void);
void Write_Dev_Param(void);
//////////////////////////////////////////////////
/// bar
#define STX  0x02
#define LF   0x0A
#define CR   0x0D

#define SCAN_CODE_TIMEOUT             MS_TO_TICK_HIGH(60000UL)
#define MAX_BAR_CODE                  32


#define MAX_BYTE_TO_BYTE_DELAY          US_TO_TICK_UL(500000)   // 字符间最长间隔
#define _20_MS                          US_TO_TICK_UL(20000)
#define TICK_TIMEOUT                    US_TO_TICK_UL(500000)  // 等待回应的最长时间


extern uchar bar_code[MAX_BAR_CODE];    // 最后扫描的条码
extern ushort scan_timestamp;           // 最后一次条码扫描时间
extern bit bar_not_implanted;           // 新条码未更新植入到试剂孔位
extern bit check_reply;                 // 等待回复校验

void Append_Bar(char * bar,uchar len);
bit Output_Diff_Only(void);
void Scan_Code(bit enable);             // 启动/停止扫描条码
void Start_Scan(uchar sample_index);
void Active_Scan(void);
void Stop_Scan(uchar sample_index);
void Scan_Cntrl(void);
void Process_Scanbar(void);
uchar Mbar_Count(void);
uchar Rack_Scan_Finished(void);
#endif // CONFIG_H
